package cn.matrix42.potoo.format.markdown;

import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ServiceLoader;

import cn.matrix42.potoo.format.markdown.element.MarkdownElement;
import cn.matrix42.potoo.format.markdown.element.text.paragraph.Paragraph;
import cn.matrix42.potoo.format.markdown.element.text.paragraph.Toc;
import cn.matrix42.potoo.format.markdown.element.text.title.Heading;
import cn.matrix42.potoo.format.markdown.io.MarkdownWriter;
import cn.matrix42.potoo.format.markdown.parser.MarkdownElementParser;
import cn.matrix42.potoo.format.markdown.element.chart.table.Table;
import cn.matrix42.potoo.format.markdown.conf.MarkdownConfig;
import cn.matrix42.potoo.lang.Preconditions;

public class Markdown extends MarkdownElement implements MarkdownElementParser<Markdown> {

    private final List<MarkdownElement> markdownElements = new ArrayList<>();

    public Markdown() {
    }

    public Markdown(MarkdownConfig config) {
        Preconditions.checkNotNull(config);
        this.context.setConfig(config);
    }

    public Toc addToc() {
        Toc toc = Toc.of();
        return addMarkdownElement(toc);
    }

    public Heading addTitle(int level) {
        Heading heading = Heading.of(level);
        return addMarkdownElement(heading);
    }

    public Heading addTitle(int level, String content) {
        Heading heading = Heading.of(level, content);
        return addMarkdownElement(heading);
    }

    public Paragraph addParagraph(String content) {
        Paragraph paragraph = Paragraph.of(content);
        return addMarkdownElement(paragraph);
    }

    public Paragraph addNewLine() {
        Paragraph newLine = Paragraph.newLine();
        return addMarkdownElement(newLine);
    }

    public List<Paragraph> addNewLine(int n) {
        List<Paragraph> paragraphList = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            Paragraph newLine = Paragraph.newLine();
            addMarkdownElement(newLine);
            paragraphList.add(newLine);
        }
        return paragraphList;
    }

    public Table addTable(int column) {
        Table table = new Table(column);
        return addMarkdownElement(table);
    }

    public <T extends MarkdownElement> T addMarkdownElement(T markdownElement) {
        Preconditions.checkNotNull(markdownElement);
        markdownElement.setup(context);
        markdownElements.add(markdownElement);
        return markdownElement;
    }

    public boolean remove(MarkdownElement markdownElement) {
        Preconditions.checkNotNull(markdownElement);
        return markdownElements.remove(markdownElement);
    }

    public void save(String filePath, boolean append) throws IOException {
        MarkdownWriter writer = new MarkdownWriter(filePath, append);
        writer.write(this);
        writer.flush();
        writer.close();
    }

    public void save(String filePath) throws IOException {
        save(filePath, false);
    }

    @Override
    public List<String> toMarkdownStringList() {
        List<String> list = new ArrayList<>();
        for (MarkdownElement markdownElement : markdownElements) {
            list.addAll(markdownElement.toMarkdownStringList());
        }
        return list;
    }

    public static Markdown newMarkdown() {
        return new Markdown();
    }

    @Override
    public Markdown parseFrom(LinkedList<String> markdownStringQueue) {
        return null;
    }

    @Override
    public boolean canParse(LinkedList<String> markdownStringQueue) {
        ServiceLoader<MarkdownElementParser> serviceLoader = ServiceLoader.load(MarkdownElementParser.class);
        for (MarkdownElementParser parser : serviceLoader) {
            parser.canParse(markdownStringQueue);
        }
        return false;
    }

    @Override
    public boolean isLeafElement() {
        return false;
    }

    @Override
    public LinkedHashSet<Class<Markdown>> parentElements() {
        return new LinkedHashSet<>();
    }

}
